package com.kawins.supers.upload.fastdfs;

import com.kawins.supers.upload.IFileManager;
import com.kawins.supers.upload.core.FileLoadBean;
import com.kawins.supers.upload.core.IFileService;
import com.kawins.supers.upload.fastdfs.manager.FastDFSFile;
import com.kawins.supers.upload.fastdfs.pool.ConnectionPool;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class FastDFSService implements IFileManager {

    private static final Logger log = LoggerFactory.getLogger(FastDFSService.class);

    private static StorageServer storageServer;

    private static TrackerServer trackerServer;

    private IFileService fileService;

    private ConnectionPool connectionPool;
    private String fastDfsService;
    private String author;

    public StorageClient init() {
        if (StringUtils.isBlank(fastDfsService)) {
            log.warn("fastDfsService为空");
        }
        trackerServer = connectionPool.checkout();
        StorageClient storageClient = new StorageClient(trackerServer, storageServer);
        return storageClient;
    }

    @Override
    public FileLoadBean upload(MultipartFile file) {
        return upload(null, file);
    }

    @Override
    public FileLoadBean upload(String groupName, MultipartFile file) {
        if (file != null && file.getSize() > 0) {
            String ext = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            try {
                FastDFSFile fastDFSFile = new FastDFSFile(file.getBytes(), ext);
                NameValuePair[] metaList = new NameValuePair[4];
                metaList[0] = new NameValuePair("fileName", file.getOriginalFilename());
                metaList[1] = new NameValuePair("fileLength", String.valueOf(file.getSize()));
                metaList[2] = new NameValuePair("fileExt", ext);
                metaList[3] = new NameValuePair("fileAuthor", author);
                FileLoadBean fileLoadBean;
                if (StringUtils.isNotBlank(groupName)) {
                    fileLoadBean = upload(groupName, fastDFSFile, metaList);
                } else {
                    fileLoadBean = upload(fastDFSFile, metaList);
                }
                if (fileLoadBean != null) {
                    fileLoadBean.setFileExt(ext);
                    fileLoadBean.setFileName(file.getOriginalFilename());
                    fileLoadBean.setFileLength(file.getSize());
                    if (fileService != null) {
                        Object insertFile = fileService.insertFile(fileLoadBean);
                        log.info("文件[{}]已经存入文件数据库中,对应ID为:{}", file.getOriginalFilename(), insertFile.toString());
                        fileLoadBean.setFileId(insertFile);
                    }
                    return fileLoadBean;
                }
                log.warn("文件[{}]上传失败", file.getOriginalFilename());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public FileLoadBean upload(String fileName, String fileExt, byte[] file) {
        return upload(fileName, fileExt, null, file);
    }

    @Override
    public FileLoadBean upload(String fileName, String fileExt, String groupName, byte[] file) {
        if (StringUtils.isBlank(fileExt) || file == null || file.length == 0) {
            log.info("文件后缀或者文件数组为空");
            return null;
        }
        FastDFSFile fastDFSFile = new FastDFSFile(file, fileExt);
        NameValuePair[] metaList = new NameValuePair[4];
        metaList[0] = new NameValuePair("fileName", fileName);
        metaList[2] = new NameValuePair("fileExt", fileExt);
        metaList[3] = new NameValuePair("fileAuthor", author);
        FileLoadBean fileLoadBean;
        if (StringUtils.isNotBlank(groupName)) {
            fileLoadBean = upload(groupName, fastDFSFile, metaList);
        } else {
            fileLoadBean = upload(fastDFSFile, metaList);
        }
        if (fileLoadBean != null) {
            fileLoadBean.setFileExt(fileExt);
            fileLoadBean.setFileName(fileName);
            fileLoadBean.setFileLength(file.length);
            if (fileService != null) {
                Object insertFile = fileService.insertFile(fileLoadBean);
                log.info("文件[{}]已经存入文件数据库中,对应ID为:{}", fileName, insertFile.toString());
                fileLoadBean.setFileId(insertFile);
            }
            return fileLoadBean;
        }
        log.warn("文件[{}]上传失败", fileName);
        return null;
    }

    @Override
    public List<FileLoadBean> upload(MultipartFile[] files) {
        List<FileLoadBean> list = new ArrayList<>(files.length);
        for (MultipartFile multipartFile : files) {
            FileLoadBean upload = upload(multipartFile);
            list.add(upload);
        }
        return list;
    }

    @Override
    public List<FileLoadBean> upload(String groupName, MultipartFile[] files) {
        List<FileLoadBean> list = new ArrayList<>(files.length);
        for (MultipartFile multipartFile : files) {
            FileLoadBean upload = upload(groupName, multipartFile);
            list.add(upload);
        }
        return list;
    }

    @Override
    public ResponseEntity<byte[]> download(Object fileId) {
        FileLoadBean fileLoadBean = fileService.selectFile(fileId);
        if (fileLoadBean != null) {
            return download(fileLoadBean.getGroupName(), fileLoadBean.getRemoteFileName(), fileLoadBean.getFileName());
        }
        return null;
    }

    @Override
    public InputStream downloadStream(Object fileId) {
        FileLoadBean fileLoadBean = fileService.selectFile(fileId);
        return download(fileLoadBean.getGroupName(), fileLoadBean.getRemoteFileName());
    }

    @Override
    public FileLoadBean update(Object fileId, MultipartFile file) {
        delete(fileId);
        return upload(file);
    }

    @Override
    public List<FileLoadBean> update(Set<Object> fileIds, MultipartFile[] files) {
        delete(fileIds);
        return upload(files);
    }

    @Override
    public FileLoadBean update(Object fileId, String groupName, MultipartFile file) {
        delete(fileId);
        return upload(groupName, file);
    }

    @Override
    public List<FileLoadBean> update(Set<Object> fileIds, String groupName, MultipartFile[] files) {
        delete(fileIds);
        return upload(groupName, files);
    }

    @Override
    public int delete(Object fileId) {
        FileLoadBean fileLoadBean = fileService.selectFile(fileId);
        if (fileLoadBean != null) {
            fileService.deleteFile(fileId);
            return delete(fileLoadBean.getGroupName(), fileLoadBean.getRemoteFileName());
        }
        log.warn("删除文件ID:[{}],时没有在数据库中找到对应的数据", fileId);
        return 0;
    }

    @Override
    public int delete(Set<Object> fileIds) {
        int n = 0;
        for (Object fileId : fileIds) {
            n += delete(fileId);
        }
        return n;
    }

    /**
     * 下载文件(返回InputStream)
     *
     * @param groupName      组名称
     * @param remoteFileName 文件名
     * @return InputStream对象
     */
    private InputStream download(String groupName, String remoteFileName) {
        byte[] content = null;
        try {
            StorageClient storageClient = init();
            content = storageClient.download_file(groupName, remoteFileName);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return content == null ? null : new ByteArrayInputStream(content);
    }

    /**
     * 下载文件
     *
     * @param groupName      文件所在组名称
     * @param remoteFileName 文件名称
     * @param specFileName   文件类型
     * @return ResponseEntity对象
     */
    private ResponseEntity<byte[]> download(String groupName, String remoteFileName, String specFileName) {
        HttpHeaders headers = new HttpHeaders();
        byte[] content = null;
        try {
            StorageClient storageClient = init();
            content = storageClient.download_file(groupName, remoteFileName);
            headers.setContentDispositionFormData("attachment",
                    new String(specFileName.getBytes("UTF-8"), "iso-8859-1"));
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return new ResponseEntity<>(content, headers, HttpStatus.CREATED);
    }


    /**
     * 删除文件
     *
     * @param groupName      分组名称
     * @param remoteFileName 文件名称
     * @return 1成功, 0失败
     */

    public int delete(String groupName, String remoteFileName) {
        try {
            StorageClient storageClient = init();
            return storageClient.delete_file(groupName, remoteFileName);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return 0;
    }


    /**
     * 上传文件
     *
     * @param file       FastDFSFile文件
     * @param valuePairs 文件分卷信息
     * @return 文件路径
     */
    private FileLoadBean upload(FastDFSFile file, NameValuePair[] valuePairs) {
        try {
            StorageClient storageClient = init();
            String[] uploadResults;
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), valuePairs);
            if (uploadResults.length > 0) {
                String groupName = uploadResults[0];
                String remoteFileName = uploadResults[1];
                return new FileLoadBean(fastDfsService, groupName, remoteFileName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return null;
    }

    /**
     * 上传文件
     *
     * @param groupName
     * @param file
     * @param valuePairs
     * @return
     */
    private FileLoadBean upload(String groupName, FastDFSFile file, NameValuePair[] valuePairs) {
        try {
            StorageClient storageClient = init();
            String[] uploadResults;
            uploadResults = storageClient.upload_file(groupName, file.getContent(), file.getExt(), valuePairs);
            if (uploadResults.length > 0) {
                String remoteFileName = uploadResults[1];
                return new FileLoadBean(fastDfsService, groupName, remoteFileName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return null;
    }


    /**
     * base64 上传图片
     *
     * @param fileBase64 图片base64码
     * @param valuePairs 文件分卷信息
     * @return 文件路径
     */
    private FileLoadBean bufferUpload(String fileBase64, NameValuePair[] valuePairs) {
        try {
            byte[] fileBuffer = Base64.getUrlEncoder().encode(fileBase64.getBytes("utf-8"));
            StorageClient storageClient = init();
            String[] uploadResults;
            uploadResults = storageClient.upload_file(fileBuffer, 0, 0, "", valuePairs);
            if (uploadResults.length > 0) {
                String groupName = uploadResults[0];
                String remoteFileName = uploadResults[1];
                return new FileLoadBean(fastDfsService, groupName, remoteFileName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connectionPool.checkin(trackerServer);
        }
        return null;
    }

    public void setConnectionPool(ConnectionPool connectionPool) {
        this.connectionPool = connectionPool;
    }

    public void setFastDfsService(String fastDfsService) {
        char c = fastDfsService.charAt(fastDfsService.length() - 1);
        if (c != '/') {
            fastDfsService += '/';
        }
        this.fastDfsService = fastDfsService;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public IFileService getFileService() {
        return fileService;
    }

    public void setFileService(IFileService fileService) {
        this.fileService = fileService;
    }
}
